package org.reliablesource.prism.gef.editor.parts;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.List;

import org.eclipse.draw2d.ConnectionLayer;
import org.eclipse.draw2d.FreeformLayout;
import org.eclipse.draw2d.IFigure;
import org.eclipse.draw2d.MarginBorder;
import org.eclipse.draw2d.PositionConstants;
import org.eclipse.draw2d.ShortestPathConnectionRouter;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.gef.EditPart;
import org.eclipse.gef.EditPolicy;
import org.eclipse.gef.LayerConstants;
import org.eclipse.gef.Request;
import org.eclipse.gef.commands.Command;
import org.eclipse.gef.editparts.AbstractGraphicalEditPart;
import org.eclipse.gef.editpolicies.ResizableEditPolicy;
import org.eclipse.gef.editpolicies.RootComponentEditPolicy;
import org.eclipse.gef.editpolicies.XYLayoutEditPolicy;
import org.eclipse.gef.requests.ChangeBoundsRequest;
import org.eclipse.gef.requests.CreateRequest;
import org.eclipse.swt.graphics.Image;
import org.eclipse.ui.PlatformUI;
import org.reliablesource.prism.core.IPrismScreen;
import org.reliablesource.prism.gef.editor.commands.PointerLocationCreateCommand;
import org.reliablesource.prism.gef.editor.commands.PointerLocationSetConstraintCommand;
import org.reliablesource.prism.gef.editor.commands.StickyNoteCreateCommand;
import org.reliablesource.prism.gef.editor.commands.StickyNoteSetConstraintCommand;
import org.reliablesource.prism.gef.editor.figures.ScreenFigure;
import org.reliablesource.prism.gef.editor.model.PointerLocation;
import org.reliablesource.prism.gef.editor.model.ScreenAdapter;
import org.reliablesource.prism.gef.editor.model.StickyNoteAdapter;

/**
 * ScreenEditPart.java  - The a ScreenAdapter instance.
 * <p>
 * This edit part server as the main diagram container, the white area where
 * everything else is in. Also responsible for the container's layout (the way
 * the container rearanges is contents) and the container's capabilities (edit
 * policies).
 * </p>
 * <p>
 * This edit part must implement the PropertyChangeListener interface, so it can
 * be notified of property changes in the corresponding model element.
 * </p>
 * 
 * @author Dennis Park
 */
public class ScreenEditPart extends AbstractGraphicalEditPart implements
		PropertyChangeListener {

	/**
	 * Upon activation, attach to the model element as a property change
	 * listener.
	 */
	public void activate() {
		if (!isActive()) {
			super.activate();
			getCastedModel().getScreen().addPropertyChangeListener(this);
			
			
		}
	}


	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.gef.editparts.AbstractEditPart#createEditPolicies()
	 */
	protected void createEditPolicies() {
		// disallows the removal of this edit part from its parent
		installEditPolicy(EditPolicy.COMPONENT_ROLE,
				new RootComponentEditPolicy());

		// handles constraint changes (e.g. moving and/or resizing) of model
		// elements
		// and creation of new model elements
		installEditPolicy(EditPolicy.LAYOUT_ROLE, new PlanXYLayoutEditPolicy());
		
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.gef.editparts.AbstractGraphicalEditPart#createFigure()
	 */
	protected IFigure createFigure() {
		ScreenFigure f = new ScreenFigure();
		try {
			Image plan = new Image(PlatformUI.getWorkbench().getDisplay(),
					(String) ((ScreenAdapter) getModel())
							.getPropertyValue(IPrismScreen.IMAGE_PATH));
			f.setImage(plan);
		} catch (Exception ex) {
			// image path not set
		}

		f.setBorder(new MarginBorder(10));
		f.setLayoutManager(new FreeformLayout());
		
		// Create the static router for the connection layer
		ConnectionLayer connLayer = (ConnectionLayer)getLayer(LayerConstants.CONNECTION_LAYER);
		connLayer.setConnectionRouter(new ShortestPathConnectionRouter(f));

		return f;
	}

	/**
	 * Upon deactivation, detach from the model element as a property change
	 * listener.
	 */
	public void deactivate() {
		if (isActive()) {
			super.deactivate();
			getCastedModel().getScreen().removePropertyChangeListener(this);
		}
	}

	private ScreenAdapter getCastedModel() {
		return (ScreenAdapter) getModel();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.gef.editparts.AbstractEditPart#getModelChildren()
	 */
	protected List getModelChildren() {
			return (getCastedModel()).getModelChildren(); // return
		// a
		// list
		// of
		// shapes
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see java.beans.PropertyChangeListener#propertyChange(PropertyChangeEvent)
	 */
	public void propertyChange(final PropertyChangeEvent evt) {
		String prop = evt.getPropertyName();
		// these properties are fired when Shapes are added into or removed from
		// the ShapeDiagram instance and must cause a call of refreshChildren()
		// to update the diagram's contents.
		if (ScreenAdapter.CHILD_ADDED_PROP.equals(prop)
				|| ScreenAdapter.CHILD_REMOVED_PROP.equals(prop)) {
			refreshChildren();
		}
	}

	/**
	 * EditPolicy for the Figure used by this edit part. Children of
	 * XYLayoutEditPolicy can be used in Figures with XYLayout.
	 */
	private static class PlanXYLayoutEditPolicy extends XYLayoutEditPolicy {

		protected Command createAddCommand(EditPart child, Object constraint) {
			return null;
		}

		/*
		 * (non-Javadoc)
		 * 
		 * @see ConstrainedLayoutEditPolicy#createChangeConstraintCommand(ChangeBoundsRequest,
		 *      EditPart, Object)
		 */
		protected Command createChangeConstraintCommand(
				ChangeBoundsRequest request, EditPart child, Object constraint) {
			if (child instanceof StickyNoteEditPart
					&& constraint instanceof Rectangle) {
				// return a command that can move and/or resize a Shape
				return new StickyNoteSetConstraintCommand((StickyNoteAdapter) child
						.getModel(), request, (Rectangle) constraint, child.getParent());
			} else if (child instanceof PointerLocationEditPart
					&& constraint instanceof Rectangle) {
				return new PointerLocationSetConstraintCommand(
						(PointerLocation) child.getModel(), request,
						(Rectangle) constraint, child.getParent());
			}
			return super.createChangeConstraintCommand(request, child,
					constraint);
		}

		/*
		 * (non-Javadoc)
		 * 
		 * @see ConstrainedLayoutEditPolicy#createChangeConstraintCommand(EditPart,
		 *      Object)
		 */
		protected Command createChangeConstraintCommand(EditPart child,
				Object constraint) {
			// if(child instanceof PointerLocationEditPart && constraint
			// instanceof
			// Rectangle){
			// return new
			// PointerLocationSetConstraintCommand((PointerLocation)child.getModel(),
			// (Rectangle)constraint);
			// }
			// not used in this example
			return null;
		}

		/*
		 * (non-Javadoc)
		 * 
		 * @see LayoutEditPolicy#getCreateCommand(CreateRequest)
		 */
		protected Command getCreateCommand(final CreateRequest request) {
			Object childClass = request.getNewObjectType();
			if (childClass == StickyNoteAdapter.class) {
				// return a command that can add a Shape to a ShapesDiagram
				return new StickyNoteCreateCommand(
						(StickyNoteAdapter) request.getNewObject(), 
						(ScreenAdapter) getHost().getModel(),
						(Rectangle) getConstraintFor(request));
						
			} else if (childClass == PointerLocation.class)
				return new PointerLocationCreateCommand(
						(PointerLocation) request.getNewObject(),
						(ScreenAdapter) getHost().getModel(),
						(Rectangle) getConstraintFor(request));
			return null;
		}

		protected Command getDeleteDependantCommand(final Request request) {
			return null;
		}

		protected EditPolicy createChildEditPolicy(final EditPart child) {
			if (child instanceof StickyNoteEditPart) {
				ResizableEditPolicy policy = new ResizableEditPolicy();
				policy.setResizeDirections(PositionConstants.EAST
						| PositionConstants.WEST | PositionConstants.NORTH
						| PositionConstants.SOUTH);
				return policy;
			}
			return null;
		}
	}
}
